Skip to content

refactor(gfql): fuse polars seeded RETURN-dst helper into one collect_all (#1755)#1765

Closed
lmeyerov wants to merge 1 commit into
masterfrom
perf/gfql-seeded-polars-fused-collect
Closed

refactor(gfql): fuse polars seeded RETURN-dst helper into one collect_all (#1755)#1765
lmeyerov wants to merge 1 commit into
masterfrom
perf/gfql-seeded-polars-fused-collect

Conversation

@lmeyerov

Copy link
Copy Markdown
Contributor

What

_seeded_typed_return_dst_polars now composes its seed-first reduction as one lazy plan (semi-joins over drop_nulls()'d id sets) and collects once via pl.collect_all([dstn, edges]), replacing ~8 eager ops (19 internal collects/exec). The empty-seed early return is subsumed (empty flows through to schema-identical empty frames). Value-identical rows; row order may differ (documented contract). Also removes the whole is_in(...implode()) deprecation surface.

Honest perf note

Hypothesis was collect-overhead dominance (as in the two-star OLAP lane, where fusion won 30-40%). Refuted here: profiling shows the single fused collect takes ~3.0ms itself — this path is compute-dominated (columnar scans over the edge frame), so fusion is perf-neutral (dgx same-session: median 3.38→3.23ms, min ~2.2; within noise). Shipping as a simplification, not a speedup. The real ≤2ms lever for seeded polars is engaging the resident #1658 adjacency index from the cypher fast path — follow-up, tracked in plans/gfql-benchmark-numbers.

Testing

Full seeded suite (51) green, incl. the polars gate tests (LazyFrame/mixed-engine decline, null-id parity, labels precedence) and the per-engine differential sweep; dgx 4-engine probe: engaged + parity on all engines.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Y6dQEcjdazEnzuvuwf73ZL

…#1755)

The eager form paid ~19 fixed-cost collects per execution (~70% of the fast
path's time, same profile signature as the two-star OLAP lane). The same
seed-first reduction now composes as one lazy plan over semi-joins on
drop_nulls()'d id sets and collects once via pl.collect_all([dstn, edges]).
Value-identical rows (row order may differ — documented contract); the
empty-seed early return is subsumed (empty seed flows through to empty,
schema-identical frames).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6dQEcjdazEnzuvuwf73ZL
@lmeyerov
lmeyerov force-pushed the perf/gfql-seeded-polars-fused-collect branch from 607f42c to 052a6f7 Compare July 21, 2026 22:34
@lmeyerov

Copy link
Copy Markdown
Contributor Author

Closing as obsolete rather than rebasing — three reasons, two from this PR's own body:

  1. Perf-neutral by its own measurement: the fusion hypothesis was refuted (compute-dominated path; the single fused collect costs ~3.0ms itself). Pure style refactor.
  2. Architecturally superseded by perf(gfql): seeded typed-hop fast paths use resident indexes (#1658 × #1755) #1768/perf(gfql): resident-index gathers engage for property-seeded lookups (SF1-vs-Neo4j lane) #1770 (both shipped in 0.58.0): _seeded_typed_return_dst_polars on master now interleaves eager resident-index gathers (CSR + node-id positional lookups) with per-stage scan fallbacks — a whole-function lazy collect_all plan can't be rebased onto that without undoing the index decoupling or re-interleaving eager gathers into the lazy plan. Complexity with no measured gain.
  3. The deprecation payload is already handled on master: the is_in(Series) deprecation (polars#22149) is mitigated via the documented .implode() pattern, cited in the code comments.

If a semi-join/lazy form is wanted later, it should be designed against the post-index helper shape (and only with a measured win). Reopen if that reading is wrong.

🤖 Generated with Claude Code

@lmeyerov lmeyerov closed this Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant